﻿using System.Linq;
using CID.Domain.Operations;
using CID.Tests.Support;
using NUnit.Framework;

namespace CID.Domain.Persistence.Tests.Operations
{
    [TestFixture]
    class ServerPersistenceTests : BasePersistenceWithDataTests
    {
        private static void AssertAreEqual(Server expected, Server actual)
        {
            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.Name, actual.Name);
            Assert.AreEqual(expected.Address, actual.Address);
            Assert.AreEqual(expected.Enabled, actual.Enabled);
            Assert.AreEqual(expected.Location.Id, actual.Location.Id);
            CollectionAssert.AreEquivalent(expected.Assignments.Select(x => x.Id), actual.Assignments.Select(x => x.Id));
        }

        [Test]
        public void SaveNewServer_ServerShouldBeSaved()
        {
            var session = OpenSession();
            var newServer = DataProvider.CreateServer(session, OperationsData.Location1);
            session.SaveOrUpdate(newServer);
            CleanSession(session);

            Assert.AreNotEqual(NotSavedId, newServer.Id);
            session = OpenSession();
            var retrievedServer = session.Get<Server>(newServer.Id);
            AssertAreEqual(newServer, retrievedServer);
            CleanSession(session);
        }

        [Test]
        public void SaveModifiedServer_ChangesShouldBeSaved()
        {
            var session = OpenSession();
            var newServer = DataProvider.CreateServer(session, OperationsData.Location1);
            session.SaveOrUpdate(newServer);
            CleanSession(session);

            session = OpenSession();
            var modifiedServer = session.Get<Server>(newServer.Id);
            AssertAreEqual(newServer, modifiedServer); //Necessary to load lazy collections before the session is wiped out
            modifiedServer.ModifyProperty(x => x.Name);
            modifiedServer.ModifyProperty(x => x.Address);
            modifiedServer.ModifyProperty(x => x.Enabled);
            var environment = DataProvider.GetEnvironment(session, OperationsData.Environment1);
            var serverRole = DataProvider.GetServerRole(session, OperationsData.ServerRole2);
            modifiedServer.Assign(environment, serverRole);
            session.SaveOrUpdate(modifiedServer);
            CleanSession(session);

            session = OpenSession();
            var retrievedServer = session.Get<Server>(newServer.Id);
            AssertAreEqual(modifiedServer, retrievedServer);
            CleanSession(session);
        }

        [Test]
        public void DeleteServer_ServerShouldBeDeleted()
        {
            var session = OpenSession();
            var newServer1 = DataProvider.CreateServer(session, OperationsData.Location1, "Server To Delete");
            var newServer2 = DataProvider.CreateServer(session, OperationsData.Location1, "Server To Remain");
            session.SaveOrUpdate(newServer1);
            session.SaveOrUpdate(newServer2);
            CleanSession(session);

            session = OpenSession();
            var retrievedServer1 = session.Get<Server>(newServer1.Id);
            session.Delete(retrievedServer1);
            CleanSession(session);

            session = OpenSession();
            retrievedServer1 = session.Get<Server>(newServer1.Id);
            var retrievedServer2 = session.Get<Server>(newServer2.Id);
            Assert.IsNull(retrievedServer1);
            Assert.IsNotNull(retrievedServer2);
            CleanSession(session);
        }

        [Test]
        public void AssignServerMultipleTimes_AssignmentChangesShouldBeSaved()
        {
            var session = OpenSession();
            var newServer = DataProvider.CreateServer(session, OperationsData.Location1);
            var environment1 = DataProvider.GetEnvironment(session, OperationsData.Environment1);
            var environment2 = DataProvider.GetEnvironment(session, OperationsData.Environment2);
            var serverRole1 = DataProvider.GetServerRole(session, OperationsData.ServerRole1);
            newServer.Assign(environment1, serverRole1);
            newServer.Assign(environment2, serverRole1);
            session.SaveOrUpdate(newServer);
            CleanSession(session);

            session = OpenSession();
            var modifiedServer = session.Get<Server>(newServer.Id);
            AssertAreEqual(newServer, modifiedServer); //Necessary to load lazy collections before the session is wiped out
            environment1 = DataProvider.GetEnvironment(session, OperationsData.Environment1);
            environment2 = DataProvider.GetEnvironment(session, OperationsData.Environment2);
            serverRole1 = DataProvider.GetServerRole(session, OperationsData.ServerRole1);
            var serverRole2 = DataProvider.GetServerRole(session, OperationsData.ServerRole2);
            modifiedServer.Assign(environment1, serverRole2);
            modifiedServer.Assign(environment2, serverRole2);
            modifiedServer.Unassign(environment1, serverRole1);
            session.SaveOrUpdate(modifiedServer);
            CleanSession(session);

            session = OpenSession();
            var retrievedServer = session.Get<Server>(newServer.Id);
            AssertAreEqual(modifiedServer, retrievedServer);
            CleanSession(session);
        }
    }
}
